
import os
import re

currentPackageName = None
currentModule = None
modules = {}
packages = []
paramInfos = {}
currentDesc = None
currentReturn = None
currentStruct = None

class Module:
	def __init__(self, moduleName, packageName):
		self.moduleName = moduleName
		self.packageName = packageName
		self.functions = []
		self.structs = []

	def toXML(self):
		xmlString = "\t<module name=\"%s\">\n" % (self.moduleName)
		if len(self.functions):
			xmlString +="\t\t<functions>\n"
			for function in self.functions:
				xmlString += function.toXML()
			xmlString +="\t\t</functions>\n"
		if len(self.structs):
			xmlString +="\t\t<structs>\n"
			for astruct in self.structs:
				xmlString += astruct.toXML()
			xmlString +="\t\t</structs>\n"
		xmlString += "\t</module>\n"
		return xmlString

class Function:
	def __init__(self, functionName, functionType, functionReturnsPointer, functionDesc, functionReturn):
		self.functionName = functionName
		self.functionType = functionType
		self.functionReturnsPointer = functionReturnsPointer
		self.functionDesc = functionDesc
		self.functionReturn = functionReturn
		self.params = []

	def toXML(self):
		xmlString = "\t\t\t<function name=\"%s\" type=\"%s\" retPtr=\"%s\">\n" % (self.functionName, self.functionType, self.functionReturnsPointer)
		if self.functionDesc:
			xmlString += "\t\t\t\t<desc>%s</desc>\n" % (self.functionDesc)
		if self.functionReturn:
			xmlString += "\t\t\t\t<return>%s</return>\n" % (self.functionReturn)
		if len(self.params):
			xmlString += "\t\t\t\t<params>\n"
			for param in self.params:
				xmlString += param.toXML()
			xmlString += "\t\t\t\t</params>\n"
		xmlString += "\t\t\t</function>\n"
		return xmlString

class Structure:
	def __init__(self, structDesc):
		self.params = []
		self.structDesc = structDesc
	
	def setName(self, structName):
		self.structName = structName	

	def toXML(self):
		xmlString = "\t\t\t<struct name=\"%s\">\n" % (self.structName)
		if self.structDesc:
			xmlString += "\t\t\t\t<desc>%s</desc>\n" % (self.structDesc)
		if len(self.params):
			xmlString += "\t\t\t\t<params>\n"
			for param in self.params:
				xmlString += param.toXML()
			xmlString += "\t\t\t\t</params>\n"
		xmlString += "\t\t\t</struct>\n"
		return xmlString
		

class Param:
	def __init__(self, paramName,paramType,paramDesc,isPointer):
		self.paramName = paramName
		self.paramType = paramType
		self.paramDesc = paramDesc
		self.isPointer = isPointer
		
	def toXML(self):
		xmlString = "\t\t\t\t\t<param name=\"%s\" type=\"%s\" isPtr=\"%s\">%s</param>\n" % (self.paramName, self.paramType, self.isPointer, self.paramDesc)
		return xmlString

def processLine(line):
	global currentModule
	global currentPackageName
	global modules
	global paramInfos
	global currentDesc
	global currentReturn
	global currentStruct
	global packages
	
	#line = line.replace("  ", " ");

	# ADD REPLACE FOR multiple spaces, other chars

	# check for package
	m = re.compile("@package( [^}]* )").search(line)
	if m:
		currentPackageName = m.group().split(' ')[1]
		if not currentPackageName in packages:
			packages.append(currentPackageName)
	#check for module
	m = re.compile("@beginmodule( [^}]* )").search(line)
	if m:
		currentModuleName = m.group().split(' ')[1]
		if not modules.has_key(currentModuleName):
			modules[currentModuleName] = Module(currentModuleName, currentPackageName)
		currentModule = modules[currentModuleName]
	
	if line.find("@endmodule") > -1:
		currentModule = None

	if not currentModule:
		return

	m = re.compile("@return( [^}]*)").search(line)
	if m:
		currentReturn = m.group()[m.group().find(m.group().split(" ")[1]) :];  

	m = re.compile("@desc( [^}]*)").search(line)
	if m:
		currentDesc = m.group()[m.group().find(m.group().split(" ")[1]) :];  

	m = re.compile("@param( [^}]*)").search(line)
	if m:
		paramInfos[m.group().split(" ")[1]] = m.group()[m.group().find(m.group().split(" ")[2]) :];  

	if currentStruct != None:
		if line.find("}") > -1:
			currentStruct.setName(line[line.find("}")+2:])
			currentModule.structs.append(currentStruct)
			paramInfos = {}
			currentDesc = None
			currentReturn = None
			currentStruct = None
		else:
			m = re.compile("(([^}]*) ([^}]*))").search(line)
			if m:
				if m.group().find("*") > -1:
					isPointer = True
				else:
					isPointer = False
				if m.group().find("(*") > -1:
					isPointer = False
				paramName = m.group()[m.group().find(m.group().split(" ")[1].strip("\t*")):]
				if paramName in paramInfos:
					info = paramInfos[paramName]
				else:
					info = "No info"
				newParam = Param(paramName, m.group().split(" ")[0].strip("\t*"),info, isPointer)
				currentStruct.params.append(newParam)
		return

	if line.find("typedef struct") > -1:
		currentStruct = Structure(currentDesc)

	#method
	m = re.compile("(([^}]*) ([^}]*)\(([^}]*)\))").search(line)
	if m:
		g = m.group().split('(')[0].split(' ')
		if not g[len(g)-1] in currentModule.functions:
			if g[len(g)-1].find("*") > -1 or g[len(g)-2].find("*") > -1:
				retPtr = True
			else:
				retPtr = False
			newFunc = Function(g[len(g)-1].strip("*"), g[len(g)-2].strip("*"), retPtr, currentDesc, currentReturn)
			for param in m.group().split('(')[1].split(','):
				if param.find(" ") > -1:
					if param.find("*") > -1:
						isPointer = True
					else:
						isPointer = False
					paramName = param.split(' ')[1].strip('*)')
					if paramName in paramInfos:
						info = paramInfos[paramName]
					else:
						info = "No info"
					newParam = Param(paramName, param.split(' ')[0].strip('*)'),info, isPointer)
					newFunc.params.append(newParam)
			currentModule.functions.append(newFunc)
			paramInfos = {}
			currentDesc = None
			currentReturn = None

def parseSourceFile(filepath):
	file = open(filepath)
	filecontent = ""
	for line in file:
		filecontent += line

	filecontent = filecontent.replace("/*", ";")
	filecontent = filecontent.replace("\n", ";")
	filecontent = filecontent.replace("*/", ";")
	filecontent = filecontent.replace(", ", ",")
	filecontent = filecontent.replace(" ,", ",")
	finalLines = filecontent.split(";")
	for line in finalLines:
		processLine(line)
	file.close()

def parseSourceTree(path):
	print "parsing %s" % (path)
	os.chdir(path)
	allowedExts = "h c"
	for fname in os.listdir(path):
		if os.path.isdir(fname):
			print "ignoring folder %s" % (fname)
		else:
			ext = fname.split(".")[len(fname.split("."))-1]
			if ext in allowedExts.split(" "):
				parseSourceFile("%s/%s" % (path, fname))

def makeXML():
	retString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	retString += "<packages>\n"
	for package in packages:
		retString += "<package name=\"%s\">\n" % (package)
		retString += "<modules>\n"
		for module in modules:
			if modules[module].packageName == package:
				retString += modules[module].toXML()
		retString += "</modules>\n"
		retString += "</package>\n"
	retString += "</packages>\n"
	return retString

print "--- nanodoc v0.1 ---"
f = open("rgs.xml", "w")
parseSourceTree("/Users/ivansafrin/Desktop/Workshop/RGS/include")
f.write(makeXML())
f.close()
